package qc.common.core.utils;


/**
 * Crc校验工具类
 *
 * @author QuCheng Tech
 * @since 2025/11/7
 */
public class CrcUtil {
    //使用在线网站进行验证：https://www.ip33.com/crc.html
    private static final int CRC12_POLYNOMIAL = 0x80F; // 自定义多项式，需要根据具体需求设定
    private static final int CRC12_INITIAL_REMAINDER = 0xFFFF; // 初始余数，根据需要设定
    private static final int CRC12_FINAL_XOR_VALUE = 0x0000; // 最终异或值，根据需要设定
    private static final boolean CRC12_REVERSE_DATA = false; // 数据是否反向输入，根据需要设定
    private static final boolean CRC12_REVERSE_REMAINDER = true; // 余数是否反向输出，根据需要设定

    private static final int CRC16_POLYNOMIAL = 0x8005;//多项式：0x8005（x^16 + x^15 + x^2 + 1）
    private static final int CRC16_INITIAL_VALUE = 0xFFFF;// 初始值通常为0xFFFF或0x0000，取决于具体实现

    //SL427中的CRC计算，对应多项式为x7 + x6 + x5 + x2 + 1 
    public static int crc7(byte[] bytes) {
        int crc = 0x0;//0xFF
        for (byte b : bytes) {
            //先将对应字节的byte类型转换为int类型，否则超过byte类型的-127~127范围会导致后面计算错误
            int byteValue = b & 0xFF;//与1字节的0xFF做与运算
            crc ^= byteValue;// 与CRC低8位异或

            // 处理8位数据
            for (int j = 0; j < 8; j++) {
                if ((crc & 0x80) != 0) {// 如果最高位为1
                    crc = (crc >> 1) ^ 0xCA; // 0xE5=1110 0101，对应多项式为x7 + x6 + x5 + x2 + 1 ，0x1A为0xE5的位反转
                } else {
                    crc = crc >> 1;
                }
            }
        }

        return crc & 0xFF;
    }

    public static int crc12(byte[] bytes) {
        int remainder = CRC12_INITIAL_REMAINDER;
        for (byte b : bytes) {
            if (CRC12_REVERSE_DATA) {
                b = (byte) Integer.reverse(b & 0xFF);
            }
            remainder ^= ((b << 8) & 0xFFFF); // 将字节左移8位并与余数进行异或操作
            for (int bit = 0; bit < 8; bit++) { // 对每一位进行处理
                if ((remainder & 0x8000) != 0) { // 如果最高位为1
                    remainder = (remainder << 1) ^ CRC12_POLYNOMIAL; // 左移一位后与多项式进行异或操作
                } else {
                    remainder = (remainder << 1); // 否则只左移一位
                }
            }
        }
        if (CRC12_REVERSE_REMAINDER) {
            remainder = Integer.reverse(remainder); // 如果需要反向输出余数，则进行反转操作
        }
        remainder &= 0xFFF; // 确保余数只取低12位
        return remainder ^ CRC12_FINAL_XOR_VALUE; // 应用最终异或值
    }

    /**
     * CRC-16/MODBUS	x16 + x15 + x2 + 1
     *
     * @param bytes 计算CRC的字节数组
     * @return int 计算的crc数值，如果要转换为字节数组使用RadixConvertUtil.toByteArray方法
     * @author QuCheng Tech
     * @since 2025/11/8
     */
    public static int Crc16_Modbus(byte[] bytes) {
        int crc = CRC16_INITIAL_VALUE;
        for (byte b : bytes) {
            //先将对应字节的byte类型转换为int类型，否则超过byte类型的-127~127范围会导致后面计算错误
            int byteValue = b & 0xFF;//与1字节的0xFF做与运算
            crc ^= byteValue;// 与CRC低8位异或
            //crc ^= b & 0xFF; // 将字节与当前CRC寄存器进行异或运算

            // 处理8位数据
            for (int j = 0; j < 8; j++) {
                if ((crc & 0x0001) != 0) {
                    crc = (crc >> 1) ^ 0xA001; // 0xA001是0x8005的位反转
                } else {
                    crc = crc >> 1;
                }
            }
        }

        return crc & 0xFFFF;// 注意，这里返回的是最终的CRC值，通常是取反（~crc）或者不移位（取决于具体标准）
        //return ~crc;// 注意，这里返回的是最终的CRC值，通常是取反（~crc）或者不移位（取决于具体标准）
    }
}